package ru.spb.osll.myfit.fixtures.base;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.util.LinkedList;
import java.util.List;

import org.junit.Test;

import ru.spb.osll.myfit.util.CollectionUtils;
import ru.spb.osll.myfit.util.StringUtils;
import fit.Parse;
import fitnesse.wiki.WikiPageDummy;
import fitnesse.wikitext.widgets.ParentWidget;
import fitnesse.wikitext.widgets.WidgetRoot;

public class OneLineFixtureUtilsTest {
	static final String SYSTEM_LINE_SEPARATOR = System
			.getProperty("line.separator");

	public static String wiki2html(String wikiText) throws Exception {
		ParentWidget page = new WidgetRoot(wikiText + "\n", new WikiPageDummy());
		return page.render();
	}

	@Test
	public void testWiki2Html() throws Exception {
		String wikiText = "|act as|Smith|";
		String expectedHtml = "<table border=\"1\" cellspacing=\"0\">\n"
				+ "<tr><td>act as</td>\n" + "<td>Smith</td>\n"
				+ "</tr>\n</table>\n";
		expectedHtml = expectedHtml.replace("</td>\n", "</td>"
				+ SYSTEM_LINE_SEPARATOR);
		String res = wiki2html(wikiText);

		assertEquals(expectedHtml, res);
	}

	@Test
	public void testGetOneLineTable() throws Exception {
		Parse table = new Parse(
				wiki2html("|enable advanced retention on clusters|"));
		List<String> oneLineTable = OneLineFixtureUtils.getOneLineTable(table,
				new String[0]);
		assertEquals("enable advanced retention on clusters", StringUtils.join(
				oneLineTable, "|"));

		table = new Parse(
				wiki2html("|apply retention hold|ret1|using|80|threads|"));
		oneLineTable = OneLineFixtureUtils.getOneLineTable(table, new String[] {
				"ret1", "using", "80", "threads" });
		assertEquals("apply retention hold|ret1|using|80|threads", StringUtils
				.join(oneLineTable, "|"));

	}

	@Test
	public void testGetMethodName() {
		List<String> table = CollectionUtils
				.list("enable advanced retention on clusters");
		assertEquals("EnableAdvancedRetentionOnClusters", OneLineFixtureUtils
				.getMethodName(table));

		table = CollectionUtils.list("apply retention hold", "ret1", "using",
				"80", "threads");
		assertEquals("ApplyRetentionHoldUsingThreads", OneLineFixtureUtils
				.getMethodName(table));
	}

	@Test
	public void testGetMethod() throws Exception {
		assertEquals(getClass().getMethod("testGetMethod"), OneLineFixtureUtils
				.getMethod(getClass(), "TestGetMethod"));
		assertEquals(OneLineFixtureUtils.class.getMethod("getMethod",
				Class.class, String.class), OneLineFixtureUtils.getMethod(
				OneLineFixtureUtils.class, "getMethod"));
		boolean caughtException = false;
		try {
			OneLineFixtureUtils.getMethod(getClass(), "UnexistingMethod");
		} catch (OneLineFixtureException e) {
			assertEquals("Method UnexistingMethod not found in class "
					+ getClass().getName(), e.getMessage());
			caughtException = true;
		}
		assertTrue(caughtException);
	}

	public void dummyMethod() {

	}

	public boolean dummyMethodWithArgs(int res, String arg) {
		return res == 1 && arg.equals("OK");
	}

	@Test
	public void testInvokeMethodWithoutParams() throws Exception {
		assertEquals(FixtureMethodResult.NONE, OneLineFixtureUtils
				.invokeMethod(this, getClass().getMethod("dummyMethod"),
						new LinkedList<String>()));
	}

	@Test
	public void testInvokeMethodWithParams() throws Exception {
		assertEquals(FixtureMethodResult.OK, OneLineFixtureUtils.invokeMethod(
				this, getClass().getMethod("dummyMethodWithArgs", int.class,
						String.class), CollectionUtils.list("1", "OK")));
		assertEquals(FixtureMethodResult.ERROR,
				OneLineFixtureUtils.invokeMethod(this, getClass().getMethod(
						"dummyMethodWithArgs", int.class, String.class),
						CollectionUtils.list("1", "")));
		assertEquals(FixtureMethodResult.ERROR, OneLineFixtureUtils
				.invokeMethod(this, getClass().getMethod("dummyMethodWithArgs",
						int.class, String.class), CollectionUtils.list("0",
						"OK")));
	}

	@Test
	public void testInvokeMethodWrongArgs() throws Exception {
		boolean caughtException = false;
		try {
			OneLineFixtureUtils.invokeMethod(this, getClass().getMethod(
					"dummyMethod"), CollectionUtils.list("arg"));
		} catch (OneLineFixtureException e) {
			caughtException = true;
			assertEquals(
					"Wrong number of parameters for method dummyMethod expected 0 but 1 provided",
					e.getMessage());
		}
		assertTrue(caughtException);
		caughtException = false;
		try {
			OneLineFixtureUtils.invokeMethod(this, getClass().getMethod(
					"dummyMethodWithArgs", int.class, String.class),
					CollectionUtils.list("1"));
		} catch (OneLineFixtureException e) {
			caughtException = true;
			assertEquals(
					"Wrong number of parameters for method dummyMethodWithArgs expected 2 but 1 provided",
					e.getMessage());
		}
		assertTrue(caughtException);

		caughtException = false;
		try {
			OneLineFixtureUtils.invokeMethod(this, getClass().getMethod(
					"dummyMethodWithArgs", int.class, String.class),
					CollectionUtils.list("arg1", "arg2"));
		} catch (OneLineFixtureException e) {
			caughtException = true;
			assertEquals(
					"Error creating parameter of type int from value arg1", e
							.getMessage());
		}
		assertTrue(caughtException);

	}

	public static class DummyType1 {
		public String m_value;

		public DummyType1(String value) {
			m_value = value;
		}
	}

	public static class DummyType2 {
		public String m_value;

		public static DummyType2 valueOf(String value) {
			DummyType2 res = new DummyType2();
			res.m_value = value;
			return res;
		}
	}

	public static class DummyType3 {
	}

	@Test
	public void testCreateParam() {
		assertEquals(true, OneLineFixtureUtils.createParam(boolean.class,
				"true"));
		assertEquals(false, OneLineFixtureUtils.createParam(Boolean.class,
				"false"));
		assertEquals(10, OneLineFixtureUtils.createParam(int.class, "10"));
		assertNull(OneLineFixtureUtils.createParam(int.class, "str"));
		assertEquals("str", OneLineFixtureUtils
				.createParam(String.class, "str"));
		assertEquals("str", ((DummyType1) OneLineFixtureUtils.createParam(
				DummyType1.class, "str")).m_value);
		assertEquals("str", ((DummyType2) OneLineFixtureUtils.createParam(
				DummyType2.class, "str")).m_value);
		assertNull(OneLineFixtureUtils.createParam(DummyType3.class, "str"));
	}
}
